home *** CD-ROM | disk | FTP | other *** search
/ Aminet 41 / Aminet 41 (2001)(Schatztruhe)[!][Feb 2001].iso / Aminet / dev / c / libiconv_src.lha / src / iconv_string.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-07  |  4.3 KB  |  151 lines

  1. #include "iconv_string.h"
  2. #include <iconv.h>
  3. #include <errno.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6.  
  7. #define tmpbufsize 4096
  8.  
  9. int iconv_string (const char* tocode, const char* fromcode,
  10.                   const char* start, const char* end,
  11.                   char** resultp, size_t* lengthp)
  12. {
  13.   iconv_t cd = iconv_open(tocode,fromcode);
  14.   size_t length;
  15.   char* result;
  16.   if (cd == (iconv_t)(-1)) {
  17.     if (errno != EINVAL)
  18.       return -1;
  19.     /* Unsupported fromcode or tocode. Check whether the caller requested
  20.        autodetection. */
  21.     if (!strcmp(fromcode,"autodetect_utf8")) {
  22.       int ret;
  23.       /* Try UTF-8 first. There are very few ISO-8859-1 inputs that would
  24.          be valid UTF-8, but many UTF-8 inputs are valid ISO-8859-1. */
  25.       ret = iconv_string(tocode,"UTF-8",start,end,resultp,lengthp);
  26.       if (!(ret < 0 && errno == EILSEQ))
  27.         return ret;
  28.       ret = iconv_string(tocode,"ISO-8859-1",start,end,resultp,lengthp);
  29.       return ret;
  30.     }
  31.     if (!strcmp(fromcode,"autodetect_jp")) {
  32.       int ret;
  33.       /* Try 7-bit encoding first. If the input contains bytes >= 0x80,
  34.          it will fail. */
  35.       ret = iconv_string(tocode,"ISO-2022-JP-2",start,end,resultp,lengthp);
  36.       if (!(ret < 0 && errno == EILSEQ))
  37.         return ret;
  38.       /* Try EUC-JP next. Short SHIFT_JIS inputs may come out wrong. This
  39.          is unavoidable. People will condemn SHIFT_JIS.
  40.          If we tried SHIFT_JIS first, then some short EUC-JP inputs would
  41.          come out wrong, and people would condemn EUC-JP and Unix, which
  42.          would not be good. */
  43.       ret = iconv_string(tocode,"EUC-JP",start,end,resultp,lengthp);
  44.       if (!(ret < 0 && errno == EILSEQ))
  45.         return ret;
  46.       /* Finally try SHIFT_JIS. */
  47.       ret = iconv_string(tocode,"SHIFT_JIS",start,end,resultp,lengthp);
  48.       return ret;
  49.     }
  50.     if (!strcmp(fromcode,"autodetect_kr")) {
  51.       int ret;
  52.       /* Try 7-bit encoding first. If the input contains bytes >= 0x80,
  53.          it will fail. */
  54.       ret = iconv_string(tocode,"ISO-2022-KR",start,end,resultp,lengthp);
  55.       if (!(ret < 0 && errno == EILSEQ))
  56.         return ret;
  57.       /* Finally try EUC-KR. */
  58.       ret = iconv_string(tocode,"EUC-KR",start,end,resultp,lengthp);
  59.       return ret;
  60.     }
  61.     errno = EINVAL;
  62.     return -1;
  63.   }
  64.   /* Determine the length we need. */
  65.   {
  66.     size_t count = 0;
  67.     char tmpbuf[tmpbufsize];
  68.     const char* inptr = start;
  69.     size_t insize = end-start;
  70.     while (insize > 0) {
  71.       char* outptr = tmpbuf;
  72.       size_t outsize = tmpbufsize;
  73.       size_t res = iconv(cd,&inptr,&insize,&outptr,&outsize);
  74.       if (res == (size_t)(-1)) {
  75.         if (errno == EINVAL)
  76.           break;
  77.         else {
  78.           int saved_errno = errno;
  79.           iconv_close(cd);
  80.           errno = saved_errno;
  81.           return -1;
  82.         }
  83.       }
  84.       count += outptr-tmpbuf;
  85.     }
  86.     {
  87.       char* outptr = tmpbuf;
  88.       size_t outsize = tmpbufsize;
  89.       size_t res = iconv(cd,NULL,NULL,&outptr,&outsize);
  90.       if (res == (size_t)(-1)) {
  91.         int saved_errno = errno;
  92.         iconv_close(cd);
  93.         errno = saved_errno;
  94.         return -1;
  95.       }
  96.       count += outptr-tmpbuf;
  97.     }
  98.     length = count;
  99.   }
  100.   if (lengthp != NULL)
  101.     *lengthp = length;
  102.   if (resultp == NULL) {
  103.     iconv_close(cd);
  104.     return 0;
  105.   }
  106.   result = (*resultp == NULL ? malloc(length) : realloc(*resultp,length));
  107.   *resultp = result;
  108.   if (length == 0) {
  109.     iconv_close(cd);
  110.     return 0;
  111.   }
  112.   if (result == NULL) {
  113.     iconv_close(cd);
  114.     errno = ENOMEM;
  115.     return -1;
  116.   }
  117.   iconv(cd,NULL,NULL,NULL,NULL); /* return to the initial state */
  118.   /* Do the conversion for real. */
  119.   {
  120.     const char* inptr = start;
  121.     size_t insize = end-start;
  122.     char* outptr = result;
  123.     size_t outsize = length;
  124.     while (insize > 0) {
  125.       size_t res = iconv(cd,&inptr,&insize,&outptr,&outsize);
  126.       if (res == (size_t)(-1)) {
  127.         if (errno == EINVAL)
  128.           break;
  129.         else {
  130.           int saved_errno = errno;
  131.           iconv_close(cd);
  132.           errno = saved_errno;
  133.           return -1;
  134.         }
  135.       }
  136.     }
  137.     {
  138.       size_t res = iconv(cd,NULL,NULL,&outptr,&outsize);
  139.       if (res == (size_t)(-1)) {
  140.         int saved_errno = errno;
  141.         iconv_close(cd);
  142.         errno = saved_errno;
  143.         return -1;
  144.       }
  145.     }
  146.     if (outsize != 0) abort();
  147.   }
  148.   iconv_close(cd);
  149.   return 0;
  150. }
  151.